package org.ouwh.fw.model.data;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import org.ouwh.fw.util.xml.Node;

public class Struct extends Data implements Map<String, Data> {

	/**
	 * 
	 */
	private static final long serialVersionUID = 5832804855523917488L;
	private HashMap<String, Data> datas = new HashMap<String, Data>(32);
	private ArrayList<String> names = new ArrayList<String>(32);

	public Struct() {
		super();
		this.tagName = "struct";
	}

	public Struct(String name) {
		super(name);
		this.tagName = "struct";
	}

	public void addData(String nodeName, Object nodeValue) {
		if (datas.containsKey(nodeName)) {
			try {
				setValueAt(nodeName, nodeValue);
			} catch (Exception e) {
			}
		} else {
			Data data = new Data();
			data.setName(nodeName.trim());
			data.setValue(nodeValue);
			addData(data);
		}
	}

	public void addData(Data data) {
		if (!datas.containsKey(data.getName())) {
			names.add(data.getName());
		}
		datas.put(data.getName(), data);
	}

	public Data get(int index) throws Exception {
		String name = names.get(index);
		return get(name);
	}

	public Data get(String name) throws Exception {
		Data data = datas.get(name);
		if (data != null) {
			return data;
		}
		throw new Exception("Named data[" + name + "]not defined in parent node: " + this.getName());
	}

	public Iterator<String> getDataNames() {
		return names.iterator();
	}

	public Object getValueAt(String name) throws Exception {
		Data data = get(name);
		return data.getValue();
	}

	public void setValueAt(String name, Object value) throws Exception {
		Data data = get(name);
		data.setValue(value);
	}

	public void remove(String name) throws Exception {
		datas.remove(name);
		names.remove(name);
	}

	public Object init(Node node) {
		super.init(node);
		return this;
	}

	public int size() {
		return names.size();
	}

	public String toString() {
		StringBuffer tmp = new StringBuffer();
		for (int i = 0; i < tabCount; i++) {
			tmp.append("\t");
		}
		tmp.append("<");
		tmp.append(tagName);
		tmp.append(" id=\"");
		tmp.append(getName());
		tmp.append("\" >\n");
		tabCount++;
		Iterator<String> it = getDataNames();
		while (it.hasNext()) {
			String name = it.next();
			Data node = (Data) datas.get(name);
			tmp.append(node.toString());
		}
		tabCount--;
		for (int i = 0; i < tabCount; i++) {
			tmp.append("\t");
		}
		tmp.append("</");
		tmp.append(tagName);
		tmp.append(">\n");
		return tmp.toString();
	}

	public Object clone() throws CloneNotSupportedException {
		Struct toClone = null;
		toClone = new Struct();
		toClone.setName(getName());
		toClone.tagName = this.tagName;
		Iterator<String> it = getDataNames();
		while (it.hasNext()) {
			String name = it.next();
			try {
				toClone.addData((Data) (get(name).clone()));
			} catch (Exception e) {
				throw new CloneNotSupportedException();
			}
		}
		return toClone;
	}

	@Override
	public void clear() {
		datas.clear();
		names.clear();
	}

	@Override
	public boolean containsKey(Object key) {
		return datas.containsKey(key);
	}

	@Override
	public boolean containsValue(Object value) {
		return datas.containsValue(value);
	}

	@Override
	public Set<java.util.Map.Entry<String, Data>> entrySet() {
		return datas.entrySet();
	}

	@Override
	public Data get(Object key) {
		return datas.get(key);
	}

	@Override
	public boolean isEmpty() {
		return datas.isEmpty();
	}

	@Override
	public Set<String> keySet() {
		return datas.keySet();
	}

	@Override
	public Data put(String key, Data value) {
		addData(key, value);
		return null;
	}

	@Override
	public void putAll(Map<? extends String, ? extends Data> m) {
		Iterator<?> it = m.keySet().iterator();
		while (it.hasNext()) {
			String key = (String) it.next();
			Data value = m.get(key);
			put(key, value);
		}
	}

	@Override
	public Data remove(Object key) {
		names.remove(key);
		return datas.remove(key);
	}

	@Override
	public Collection<Data> values() {
		return datas.values();
	}

}
